package Q15_04_Deadlock_Free_Class;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.concurrent.locks.Lock;
public class LockFactory {
private static LockFactory instance;
private int numberOfLocks = 5; /* default */
private LockNode[] locks;
/* Maps from a process or owner to the order that the owner claimed it would call the locks in */
private HashMap<Integer, LinkedList<LockNode>> lockOrder;
private LockFactory(int count) {
numberOfLocks = count;
locks = new LockNode[numberOfLocks];
lockOrder = new HashMap<Integer, LinkedList<LockNode>>();
for (int i = 0; i < numberOfLocks; i++) {
locks[i] = new LockNode(i, count);
}
}
public static LockFactory getInstance() {
return instance;
}
public static LockFactory initialize(int count) {
if (instance == null) {
instance = new LockFactory(count);
}
return instance;
}
public boolean hasCycle(HashMap<Integer, Boolean> touchedNodes, int[] resourcesInOrder) {
/* check for a cycle */
for (int resource : resourcesInOrder) {
if (touchedNodes.get(resource) == false) {
LockNode n = locks[resource];
if (n.hasCycle(touchedNodes)) {
return true;
}
}
}
return false;
}
/* To prevent deadlocks, force the processes to declare upfront what order they will
* need the locks in. Verify that this order does not create a deadlock (a cycle in a directed graph)
*/
public boolean declare(int ownerId, int[] resourcesInOrder) {
HashMap<Integer, Boolean> touchedNodes = new HashMap<Integer, Boolean>();
/* add nodes to graph */
int index = 1;
touchedNodes.put(resourcesInOrder[0], false);
for (index = 1; index < resourcesInOrder.length; index++) {
LockNode prev = locks[resourcesInOrder[index - 1]];
LockNode curr = locks[resourcesInOrder[index]];
prev.joinTo(curr);
touchedNodes.put(resourcesInOrder[index], false);
}
/* if we created a cycle, destroy this resource list and return false */
if (hasCycle(touchedNodes, resourcesInOrder)) {
for (int j = 1; j < resourcesInOrder.length; j++) {
LockNode p = locks[resourcesInOrder[j - 1]];
LockNode c = locks[resourcesInOrder[j]];
p.remove(c);
}
return false;
}
/* No cycles detected. Save the order that was declared, so that we can verify that the
* process is really calling the locks in the order it said it would. */
LinkedList<LockNode> list = new LinkedList<LockNode>();
for (int i = 0; i < resourcesInOrder.length; i++) {
LockNode resource = locks[resourcesInOrder[i]];
list.add(resource);
}
lockOrder.put(ownerId, list);
return true;
}
/* Get the lock, verifying first that the process is really calling the locks in the order
* it said it would. */
public Lock getLock(int ownerId, int resourceID) {
LinkedList<LockNode> list = lockOrder.get(ownerId);
if (list == null) {
return null;
}
LockNode head = list.getFirst();
if (head.getId() == resourceID) {
list.removeFirst();
return head.getLock();
}
return null;
}
}